#ifndef _SIGNALMANAGER_H_
#define _SIGNALMANAGER_H_
#include <string>
#include <SECore/Signal.h>
#include <SECore/Ecs/Component.h>
#include <unordered_map>

namespace SEngine
{
    class SignalManager
    {
    public:
        virtual ~SignalManager() = default;

        void OnAddComponent(IComponent& comp) {}
        void OnRemoveComponent(IComponent& comp) {
            m_compSlotsTable.erase(comp.Hash());
        }

        template<typename... Args>
        void Register(const std::string & name) {
            m_signalsTable.emplace(name, std::make_unique<Signal<Args...>>());
        }
        template<typename Comp, typename... Args>
        void Subscribe(const std::string & name, typename Signal<Args...>::Fn && fn) {
            auto id = typeid(Comp::CompType).hash_code();
            if (m_signalsTable.find(name) != m_signalsTable.end()) {
                Signal<Args...> & signal = static_cast<Signal<Args...>&>(*m_signalsTable[name]);
                auto flag = std::make_shared<int>();
                signal.AddSlot([flag = std::weak_ptr(flag), fn = std::move(fn)](Args... args) { 
                    if (flag.expired()) {
                        return SlotState::Once;
                    }
                    return fn(args...);
                });
                m_compSlotsTable[id].emplace_back(flag);
            }
        }
        template<typename... Args>
        void Invoke(const std::string & name, Args... args) {
            if (m_signalsTable.find(name) != m_signalsTable.end()) {
                Signal<Args...> & signal = static_cast<Signal<Args...>&>(*m_signalsTable[name]);
                signal.Invoke(args...);
            }
        }
    private:
        std::unordered_map<std::string, std::unique_ptr<ISignal>> m_signalsTable;
        std::unordered_map<size_t, std::vector<std::shared_ptr<int>>> m_compSlotsTable;
    };
} // namespace SEngine


#endif